package test.base.medium.ffmpeg;

import static org.bytedeco.ffmpeg.global.avcodec.*;

import static org.bytedeco.ffmpeg.global.avformat.*;

import static org.bytedeco.ffmpeg.global.avutil.*;
import static org.bytedeco.ffmpeg.global.swscale.sws_freeContext;

import java.io.IOException;
import java.io.OutputStream;

import org.bytedeco.ffmpeg.avcodec.AVCodec;
import org.bytedeco.ffmpeg.avcodec.AVCodecContext;
import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.avformat.AVIOContext;
import org.bytedeco.ffmpeg.avformat.AVOutputFormat;
import org.bytedeco.ffmpeg.avformat.AVStream;
import org.bytedeco.ffmpeg.avutil.AVDictionary;
import org.bytedeco.ffmpeg.avutil.AVRational;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FrameRecorder.Exception;

import hyl.core.MyFun;
import hyl.core.run.IFilter;
import hyl.core.run.MyRun;

public class RtmpFilter2 implements IFilter<AVPacket> {

///////////////////输出/////////
//输出引擎
	AVFormatContext 输出引擎 = null;
	AVFormatContext 输入引擎 = null;	
	// 编码器
	AVCodecContext 视频编码器 = null;
	AVCodecContext 音频编码器 = null;
	AVRational av帧率=null; //以视频帧为基准
	
	AVStream 视频输出流;
	AVStream 音频输出流;

	OutputStream 输出流 = null;
	AVOutputFormat oformat = null;
	boolean 是否帧交错 = false;


	public 	void ini(String 输出路径){	
			try {
				 step1(输出路径);			
			} catch (IOException e) {
				e.printStackTrace();
				release();
			}
	}
	
	String _url;
	String 输出格式名="flv";
	String  step1( String 输出路径) throws IOException {

		if (MyFun.isEmpty(输出路径))
			return "路径不能为空";
		_url=输出路径;
		
		// 查找匹配的输出格式
		//		if (帧率>1) {
		//			this.av视频帧率=帧率;
		//		}
		
		
		if (输出路径.startsWith("rtmp://"))
			 输出格式名="flv";
		else if (输出路径.startsWith("udp://"))
			 输出格式名="mpegts";
		else
			return "输出格式不对";
		 
		输出引擎 = new AVFormatContext(null);
		if (avformat_alloc_output_context2(输出引擎, null, 输出格式名, 输出路径) <0) {
			throw new Exception("avformat_alloc_context2() error:\t无法创建媒体上下文");
		}
		oformat=输出引擎.oformat();
		if ((输出引擎.flags() & AVFMT_GLOBALHEADER) == AVFMT_GLOBALHEADER) {
			输出引擎.flags(输出引擎.flags() | AV_CODEC_FLAG_GLOBAL_HEADER);

		}
		// Dump Format------------------
		av_dump_format(输出引擎, 0, 输出路径, 1);
		// 打开输出URL（Open output URL）
	
		int ret = 0;
		if ( (oformat.flags() & AVFMT_NOFILE) == 0) {
			AVIOContext pb = new AVIOContext(null);
			if ((ret = avio_open(pb, 输出路径, AVIO_FLAG_WRITE)) < 0) {
				return "avio_open() 无法开打输出文件";
			}
			输出引擎.pb(pb);
			System.out.println("打开数据文件");
		}
	
		AVDictionary options = new AVDictionary(null);
		// 写文件头（Write file header）写入空的头文件
		ret = avformat_write_header(输出引擎, options);
		 if (ret < 0) {
			 throw new Exception("avformat_write_header() error:\t无法写入头文件");
		    }
		开始时间 = av_gettime();
		return null;
	}

	Long 开始时间 = 0L;

	public String bind(AVFormatContext 输入引擎) {
		if (输入引擎 == null)
			return "缺少输入引擎";

		this.输入引擎 = 输入引擎;
		// 从输入设备 分流出视频流和音频流
		for (int idx = 0; idx < 输入引擎.nb_streams(); idx++) {
			AVStream inputStream = 输入引擎.streams(idx);
			if (inputStream.codecpar().codec_type() == AVMEDIA_TYPE_VIDEO) {
				step3_视频(inputStream, idx);
			} else if (inputStream.codecpar().codec_type() == AVMEDIA_TYPE_AUDIO) {
				step3_音频(inputStream, idx);
			}
		}

		return null;
	}


	String step3_视频(AVStream 输入流, int 索引) {
		if (输入流 == null)
			return "输入流为空";

		int codecid = 输入流.codecpar().codec_id();
		AVCodec 编码 = avcodec_find_encoder(codecid);// 音频为audio_codec

		// 声明输出流,并初始化
		视频输出流 = avformat_new_stream(输出引擎, 编码);
		// 声明编码器
		if ((视频编码器 = avcodec_alloc_context3(编码)) == null) {// 需要使用avcodec_free_context释放
			avcodec_free_context(视频编码器);
			视频编码器 = null;
		}

		AVCodecParameters inparam = 输入流.codecpar();

		// 大部分参数的复制都在这句
		avcodec_parameters_to_context(视频编码器, 输入流.codecpar());
		视频输出流.time_base(输入流.time_base())	;
		if ((输出引擎.flags() & AVFMT_GLOBALHEADER) == AVFMT_GLOBALHEADER) {
			视频编码器.flags(视频编码器.flags() | AV_CODEC_FLAG_GLOBAL_HEADER);
		}

	
		AVRational 宽高比 = inparam.sample_aspect_ratio();
		视频编码器.sample_aspect_ratio(宽高比);
		视频输出流.sample_aspect_ratio(宽高比);

		//设置帧率, 调整时间基线
		AVRational 帧率 = 输入流.r_frame_rate();
		AVRational supported_framerates = 编码.supported_framerates();
		if (supported_framerates != null) {
			int idx = av_find_nearest_q_idx(帧率, supported_framerates);
			av帧率 = supported_framerates.position(idx);
		}else
		{
			av帧率=帧率;
		}
		
		//不改变帧率字节输出
		AVRational	time_base = avutil.av_inv_q(av帧率);
		视频编码器.time_base(time_base);
		视频输出流.time_base(time_base);
		视频输出流.codec().time_base(time_base); 
		return null;
	}

	String step3_音频(AVStream 输入流, int 索引) {
		if (输入流 == null)
			return "输入流为空";

		int codecid = 输入流.codecpar().codec_id();
		AVCodec 编码 = avcodec_find_encoder(codecid);// 音频为audio_codec

		// 声明输出流,并初始化
		音频输出流 = avformat_new_stream(输出引擎, 编码);
		// 声明编码器
		if ((音频编码器 = avcodec_alloc_context3(编码)) == null) {// 需要使用avcodec_free_context释放
			avcodec_free_context(音频编码器);
			音频编码器 = null;
		}

		AVCodecParameters inparam = 输入流.codecpar();

		// 大部分参数的复制都在这句
		avcodec_parameters_to_context(音频编码器,inparam);
		if ((输出引擎.flags() & AVFMT_GLOBALHEADER) == AVFMT_GLOBALHEADER) {
			音频编码器.flags(音频编码器.flags() | AV_CODEC_FLAG_GLOBAL_HEADER);
		}
		AVRational 帧率 = 输入流.r_frame_rate();
		AVRational time_base = av_inv_q(帧率);
		音频编码器.time_base(time_base);
		音频输出流.time_base(time_base);
		音频输出流.codec().time_base(time_base); 
		return null;
	}

//
//	void 同步(  AVStream 输入流,AVStream 输出流,int idx,AVPacket avPacket  ){	
//		av_packet_rescale_ts(avPacket, 输入流.time_base(), 输出流.time_base());
//		avPacket.stream_index(idx);
//		avPacket.flags(avPacket.flags() | AV_PKT_FLAG_KEY);
//	}
	
	// 过滤包
	@Override
	/**
	 * return 为true 终端遍历
	 */
	public boolean where(AVPacket avPacket  ) {
		
		avPacket.pos(-1);
	//	直接输出不改变任何packet配置 包括timebase pts dts  和duration
		if (isover) {
			return false;
		}
		//av_packet_rescale_ts(avPacket, in_stream->time_base, out_stream->time_base);
		if (是否帧交错) {
			if (av_interleaved_write_frame(输出引擎, avPacket) != 0) {
				return true;
			}
		} else if (av_write_frame(输出引擎, avPacket) != 0) {
			return true;
		}
		return false;
	}
	boolean isover=false;
	public void close() {
		isover=true;
	
        /* 写入尾部 */
        av_write_trailer(输出引擎);
    	release();
	}

	void release() {
		if (视频编码器 != null) {
			avcodec_free_context(视频编码器);
			avcodec_close(视频编码器);// Close the codec
		}
		if (音频编码器 != null) {
			avcodec_free_context(音频编码器);
			avcodec_close(音频编码器);// Close the codec
		}
		if (输出引擎 != null)
			// 关闭图像源
			avformat_close_input(输出引擎);// Close the video file
	}
}

// 输出格式,输出文件
//public void 包输出(String format_name, String filename) throws Exception {

//
//
//	
//	 
//		
//		ofmt = oc.oformat();
//		video_c=out_stream.codec();
//		for (i = 0; i < ifmt_ctx.nb_streams(); i++) {
//			//根据输入流创建输出流（Create output AVStream according to input AVStream）
//			AVStream in_stream = ifmt_ctx.streams(i);
//			AVStream out_stream = avformat_new_stream(oc, in_stream.codec().codec());
//			
//			//复制AVCodecContext的设置（Copy the settings of AVCodecContext）
//			ret = avcodec_copy_context(out_stream.codec(), in_stream.codec());
//			if (ret < 0) {
//				System.out.println("无法复制上下文");
//				end();
//				return;
//		
//			}
//			
//			  if (ofmt.flags() & AVFMT_GLOBALHEADER) != 0) {
//				  out_stream.codec().flags(out_stream.codec().flags() | AV_CODEC_FLAG_GLOBAL_HEADER);
//	            }
//			  if ((oformat.flags() & AVFMT_GLOBALHEADER) != 0) {
//		            video_c.flags(video_c.flags() | AV_CODEC_FLAG_GLOBAL_HEADER);
//		        }
//		}

//		while (true) {
//			AVStream in_stream, out_stream;
//			//获取一个AVPacket（Get an AVPacket）
//			ret = av_read_frame(ifmt_ctx, &pkt);
//			if (ret < 0)
//				break;
//			//FIX：No PTS (Example: Raw H.264)
//			//Simple Write PTS
//			if(pkt.pts==AV_NOPTS_VALUE){
//				//Write PTS
//				AVRational time_base1=ifmt_ctx.streams[videoindex].time_base;
//				//Duration between 2 frames (us)
//				int64_t calc_duration=(double)AV_TIME_BASE/av_q2d(ifmt_ctx.streams[videoindex].r_frame_rate);
//				//Parameters
//				pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
//				pkt.dts=pkt.pts;
//				pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
//			}
//			//Important:Delay
//			if(pkt.stream_index==videoindex){
//				AVRational time_base=ifmt_ctx.streams[videoindex].time_base;
//				AVRational time_base_q={1,AV_TIME_BASE};
//				int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
//				int64_t now_time = av_gettime() - start_time;
//				if (pts_time > now_time)
//					av_usleep(pts_time - now_time);
//	 
//			}
//	 
//			in_stream  = ifmt_ctx.streams[pkt.stream_index];
//			out_stream = oc.streams[pkt.stream_index];

//			//Print to Screen
//			if(pkt.stream_index==videoindex){
//				printf("Send %8d video frames to output URL\n",frame_index);
//				frame_index++;
//			}
//			//ret = av_write_frame(oc, &pkt);
//			ret = av_interleaved_write_frame(oc, &pkt);
//	 
//			if (ret < 0) {
//				printf( "Error muxing packet\n");
//				break;
//			}
//			
//			av_free_packet(&pkt);
//			
//		}
//		//写文件尾（Write file trailer）
//		av_write_trailer(oc);
//	
//	    //有些格式希望流标题是分开的
//
//
//	avformat_close_input(&ifmt_ctx);
//	/* close output */
//	if (oc && !(ofmt.flags & AVFMT_NOFILE))
//		avio_close(oc.pb);
//	avformat_free_context(oc);
//	if (ret < 0 && ret != AVERROR_EOF) {
//		printf( "Error occurred.\n");
//		return -1;
//	}
//	return 0;
//}